package task

import (
	"apibe/single/src/v1/factory"
	"apibe/single/src/v1/factory/shortcut"
	"apibe/single/src/v1/share/croner"
	"apibe/single/src/v1/share/db"
	"context"
	"errors"
	"fmt"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"time"
)

func Init() {
	reload() // 每次重启都加载定时任务
	fmt.Println(11111)
	croner.TaskAddFunc("task_init", "0 0 * * *", reload) // 每天凌晨会从新加载所有的定时任务
}

// Task 定时任务
type Task struct {
	ID           primitive.ObjectID `json:"_id" bson:"_id"`
	GroupName    string             `json:"group_name" bson:"group_name"`       // 分组名称
	ApiName      string             `json:"api_name" bson:"api_name"`           // 接口名
	Body         map[string]string  `json:"body" bson:"body"`                   // 请求体
	Spec         string             `json:"cron" bson:"cron"`                   // cron
	Description  string             `json:"description" bson:"description"`     // 任务描述
	HoldUser     string             `json:"hold_user" bson:"hold_user"`         // 持有人
	FixDate      int64              `json:"fix_date" bson:"fix_date"`           // 最近修改日期
	BackFunction back               `json:"back_function" bson:"back_function"` // 回调函数
	Status       factory.Status     `json:"status" bson:"status"`               // 状态
}

type back struct {
	FunctionName string `json:"function_name" bson:"function_name"`
	Params       string `json:"params" bson:"params"`
}

// UpdateStatus 通过修改task的状态，及时停止或者开启任务
func UpdateStatus(id string, status factory.Status) error {
	ctx := context.Background()
	_id, err := primitive.ObjectIDFromHex(id)
	if err != nil {
		return err
	}
	croner.TaskRemove(id) // 先把任务删除掉
	switch status {
	case factory.NeedCheck, factory.Unused, factory.Deleted:
		_, err = db.GetMongoCollection(db.CollectionTask).UpdateByID(ctx, _id, bson.M{"$set": bson.M{"status": factory.NeedCheck}})
		if err != nil {
			return err
		}
		break
	case factory.Working:
		var t Task
		err = db.GetMongoCollection(db.CollectionTask).FindOneAndUpdate(ctx, bson.M{"_id": _id}, bson.M{"$set": bson.M{"status": factory.Working}}).Decode(&t)
		if err != nil {
			return err
		}
		croner.TaskAddFunc(id, t.Spec, t.do)
		break
	default:
		return errors.New("have no this status")
	}
	return nil
}

func reload() {
	ctx := context.Background()
	find, err := db.GetMongoCollection("task").Find(ctx, bson.M{"status": factory.Working})
	if err != nil {
		return
	}
	var tasks []Task
	err = find.All(ctx, &tasks)
	for _, t := range tasks {
		croner.TaskAddFunc(t.ID.Hex(), t.Spec, t.do)
	}
}

func (t *Task) do() {
	start := time.Now().UnixNano()
	design, err := factory.GetDesign(t.ApiName)
	if err != nil {
		return
	}
	body, status, cache, err := design.AutoAssembly(t.Body, 30*time.Second)
	duration := time.Now().UnixNano() - start
	if err == nil {
		go shortcut.ApiWatch(status, t.ApiName, duration)           // 接口性能监控
		go t.BackFunction.back(design, t.Body, body, status, cache) // 执行回调函数
	}
}
